package regex

import (
	"fmt"

	textker "gitee.com/endlesstravel/goylc/textker"
)

const (
	REGEX_TREE_NODE_ALPHA     = iota // a 单个字符。所有 ASCII 字符
	REGEX_TREE_NODE_ALPHA_SET        // [abc] 字符集或关系 : [ABc] [a-b] [CCa-b] [a-b0-2]
	// REGEX_TREE_NODE_NOT_ALPHA_SET        // [^abc] 字符集或关系，非字符集

	// REGEX_TREE_NODE_NUM                  // \d 匹配 0-9
	// REGEX_TREE_NODE_NOT_NUM              // \D 匹配非 0-9
	// REGEX_TREE_NODE_WORD                 // \w 匹配包括下划线、字母和数字的字符的任一字符。
	// REGEX_TREE_NODE_NOT_WORD             // \W 匹配除下划线、字母和数字的字符的任一字符
	// REGEX_TREE_NODE_SPACE                // \s 匹配空白字符。包括空格、制表符、换页符等。等价于[ \f\n\r\t\v]。
	// REGEX_TREE_NODE_NOT_SPACE            // \S 匹配除空白外的字符
	// REGEX_TREE_NODE_LF                   // \n 匹配回车符（LF，NL）
	// REGEX_TREE_NODE_NOT_LF               // \N 匹配除回车符外的字符
	// REGEX_TREE_NODE_CR                   // \r 匹配换行符
	// REGEX_TREE_NODE_TAB                  // \t 匹配 tab 符
	// REGEX_TREE_NODE_FF                   // \f 匹配一个换页符。等价于\x0c 和\cL。
	// REGEX_TREE_NODE_VT                   // \v 匹配一个垂直制表符。等价于\x0b 和\cK。
	// REGEX_TREE_NODE_CONTROL_WORD         // \cx 匹配由 x 指明的控制字符。例如，\cM 匹配一个 Control-M 或回车符。x的值必须为 A-Z 或 a-z 之一。否则，将 c 视为一个原义的“c”字符。
	// \unnnn \xnn \0nn

	REGEX_TREE_NODE_DOT   // . 通配符，多行模式下不匹配 \n，否则匹配 \n
	REGEX_TREE_NODE_BEGIN // ^ 匹配一行的开始
	REGEX_TREE_NODE_END   // $ 匹配行结束符
	REGEX_TREE_NODE_BOUND // \b 匹配一个单词边界，也就是指单词和空格间的位置。例如，“er\b”可以 匹配“never”中的“er”，但不能匹配“verb”中的“er”。
	// REGEX_TREE_NODE_NOT_BOUND // \B 匹配非单词边界。“er\B”能匹配“verb”中的“er”，但不能匹配“never”中的“er”。

	REGEX_TREE_NODE_OR  // RegExp1|RegExp2 或者
	REGEX_TREE_NODE_AND // RegExp1RegExp2 连接

	REGEX_TREE_NODE_0_OR_1     // RegExp? 0个或者1个
	REGEX_TREE_NODE_LOOP_RANGE // RegExp{m,n} |  m到n个 | {n},	重复n次 | {n,} 重复n次或更多次
	// REGEX_TREE_NODE_0_OR_MORE  // RegExp* 0个或者多个 {0,99999}
	// REGEX_TREE_NODE_1_OR_MORE  // RegExp+ 1个或者多个 {1,99999}
)

// 一个经常被问到的问题是：是不是只能同时使用多行模式和单行模式中的一种？
// 答案是：不是。这两个选项之间没有任何关系，除了它们的名字比较相似（以至于让人感到疑惑）以外
type regexContext struct {
	IgnoreCase              bool // 默认 false， 匹配时不区分大小写
	MutipleLineMode         bool // 默认 false， 更改^和$的含义，使它们分别在任意一行的行首和行尾匹配，  而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
	SinglelineMode          bool // 默认 false， 更改.的含义，使它与每一个字符匹配（包括换行符\n）。
	IgnorePatternWhitespace bool // 忽略表达式中的非转义空白并启用由 # 标记的注释。
}

type regexTree struct {
	Root *regexTreeNode
}

type regexAlphaRangeSet struct {
	IsRange    bool // 是否是单个 alpha 或者是多个 a-z
	FirstAlpha rune
	LastAlpha  rune
}

func makeRegexAlphaRangeSetOne(a rune) regexAlphaRangeSet {
	return regexAlphaRangeSet{
		IsRange:    true,
		FirstAlpha: a,
	}
}
func makeRegexAlphaRangeSetRange(a rune, b rune) regexAlphaRangeSet {
	return regexAlphaRangeSet{
		IsRange:    true,
		FirstAlpha: a,
		LastAlpha:  b,
	}
}

func makeRegexAlphaRangeSetRangeSet(a rune, b rune) []regexAlphaRangeSet {
	return []regexAlphaRangeSet{
		makeRegexAlphaRangeSetRange(a, b),
	}
}

type regexTreeNode struct {
	Type          int
	GrounpName    string
	ResultReverse bool // 取反语义
	FirstAlpha    rune
	MinRange      int // {m,n} 的 m
	MaxRange      int // {m,n} 的 n
	AlphaRangeSet []regexAlphaRangeSet
	Children      []*regexTreeNode // or | and
}

type MatchRange struct {
	start    int
	end      int
	content  []rune
	children []*MatchRange
}

func newAlphaMatchRange(pos int, theOne rune) *MatchRange {
	return &MatchRange{
		start:   pos,
		end:     pos,
		content: []rune{theOne},
	}
}

func newAlphaMatchRangeNoContent(pos int) *MatchRange { // 边界符等内容为 0 的
	return &MatchRange{
		start:   pos,
		end:     pos,
		content: []rune{},
	}
}
func newAlphaMatchRangeIgnore(pos int) *MatchRange { // 应被忽略的内容
	return &MatchRange{
		start:   pos,
		end:     -1,
		content: nil,
	}
}

func newAlphaMatchRangeFromChildren(chd []*MatchRange) *MatchRange {
	// TODO
	panic("TODO")
	return nil
	// a =
	// return &MatchRange{
	// 	start:    pos,
	// 	end:      pos,
	// 	content:  []rune{},
	// 	children: chd,
	// }
}

func isNoBoundVisibleWordRune(c rune) bool {
	// 0-9 a-z A-z 的字符
	return _CONST_a_RUNE <= c && c <= _CONST_z_RUNE || _CONST_A_RUNE <= c && c <= _CONST_Z_RUNE || _CONST_0_RUNE <= c && c <= _CONST_9_RUNE
}

func executeRegexTreeNode(rc *regexContext, node *regexTreeNode, tw *textker.TextWalker) (bool, *MatchRange) {
	t := node.Type
	switch t {
	case REGEX_TREE_NODE_ALPHA: // abc
		if tw.HasNext() {
			isEqual := tw.PeekNextRune() == node.FirstAlpha
			if (!node.ResultReverse && isEqual) || (node.ResultReverse && !isEqual) {
				return true, newAlphaMatchRange(tw.Pos(), tw.MoveNextRune())
			}
		}
		return false, nil
	case REGEX_TREE_NODE_DOT: // .
		if tw.HasNext() {
			if rc.SinglelineMode || tw.PeekNextRune() != _CONST_LF_RUNE { // 非单行模式，检测是否为 \n
				return true, newAlphaMatchRange(tw.Pos(), tw.MoveNextRune())
			}
		}
		return false, nil
	case REGEX_TREE_NODE_ALPHA_SET:
		if tw.HasNext() {
			nc := tw.PeekNextRune()
			if node.AlphaRangeSet == nil {
				panic("正则表达式 程序错误，无效的 node.AlphaRangeSet")
			}
			fitAnyOne := false
			for _, item := range node.AlphaRangeSet {
				if item.IsRange {
					if item.FirstAlpha <= nc && nc <= item.LastAlpha {
						fitAnyOne = true
						break
					}
				} else if item.FirstAlpha == nc {
					fitAnyOne = true
					break
				}
			}

			judge_flag := fitAnyOne
			if node.ResultReverse {
				judge_flag = !fitAnyOne
			}

			if judge_flag {
				return true, newAlphaMatchRange(tw.Pos(), tw.MoveNextRune())
			}
		}
		return false, nil
	case REGEX_TREE_NODE_BEGIN: // ^
		atFirstChar := tw.Pos() == 0 // 是否在行首
		if rc.MutipleLineMode {

			fitIt := atFirstChar || tw.HasNext() && (tw.PeekNextRune() == _CONST_LF_RUNE || tw.PeekNextRune() == _CONST_CR_RUNE)
			if fitIt {
				return true, newAlphaMatchRangeNoContent(tw.Pos())
			}

		} else {
			if atFirstChar {
				return true, newAlphaMatchRangeNoContent(tw.Pos())
			}
		}
		return false, nil

	case REGEX_TREE_NODE_END: // $
		atLastPos := !tw.HasNext() // 是否在行首尾部 EOF
		if rc.MutipleLineMode {

			// 匹配\n之前的位置以及字符串结束前的位置
			fitIt := atLastPos || tw.HasNext() && (tw.PeekNextRune() == _CONST_LF_RUNE || tw.PeekNextRune() == _CONST_CR_RUNE)
			if fitIt {
				return true, newAlphaMatchRangeNoContent(tw.Pos())
			}

		} else {
			if atLastPos {
				return true, newAlphaMatchRangeNoContent(tw.Pos())
			}
		}
		return false, nil

	case REGEX_TREE_NODE_BOUND: // 匹配一个单词边界，也就是指单词和空格间的位置。例如，“er\b”可以 匹配“never”中的“er”，但不能匹配“verb”中的“er”。
		isBound := false
		if tw.HasNext() && tw.HasCurrent() {
			is_vbound_current := isNoBoundVisibleWordRune(tw.CurrentRune())
			is_vbound_next := isNoBoundVisibleWordRune(tw.PeekNextRune())
			isBound = !is_vbound_current && is_vbound_next || is_vbound_current && !is_vbound_next
		}

		resultIsOk := isBound
		if node.ResultReverse {
			resultIsOk = !isBound
		}

		return resultIsOk, newAlphaMatchRangeNoContent(tw.Pos())
	case REGEX_TREE_NODE_OR:
		chd := node.Children
		if chd == nil {
			chd = make([]*regexTreeNode, 0)
		}
		nowPos := tw.Pos()
		for _, item := range chd {
			success, mr := executeRegexTreeNode(rc, item, tw)
			if success {
				return success, mr
			}
			tw.SetPos(nowPos) // 回溯
		}
		return false, nil
	case REGEX_TREE_NODE_AND:
		chd := node.Children
		if chd == nil {
			chd = make([]*regexTreeNode, 0)
		}
		nowPos := tw.Pos()
		cca := make([]*MatchRange, 0, 10)
		for _, item := range chd {
			success, mr := executeRegexTreeNode(rc, item, tw)
			if !success {
				tw.SetPos(nowPos) // 回溯
				return false, nil
			}
			cca = append(cca, mr)
		}
		return true, newAlphaMatchRangeFromChildren(cca)

	case REGEX_TREE_NODE_0_OR_1:
		nowPos := tw.Pos()
		chd := node.Children
		if chd == nil || len(chd) != 1 {
			panic("正则表达式节点错误，? 内子元素应只有1个： " + fmt.Sprint(t))
		}

		theOne := chd[0]
		success, mr := executeRegexTreeNode(rc, theOne, tw)
		if success {
			return true, mr
		}

		tw.SetPos(nowPos) // 回溯
		return true, newAlphaMatchRangeIgnore(nowPos)

	case REGEX_TREE_NODE_LOOP_RANGE:
		nowPos := tw.Pos()
		chd := node.Children
		if chd == nil || len(chd) != 1 {
			panic("正则表达式节点错误，* 或 + 或 {m,n} 内子元素应只有1个： " + fmt.Sprint(t))
		}

		theOne := chd[0]
		cca := make([]*MatchRange, 0, 10)
		for {
			success, mr := executeRegexTreeNode(rc, theOne, tw)
			if !success {
				break
			}
			cca = append(cca, mr)

			if len(cca) == node.MaxRange { // 已到达最大
				break
			}
		}

		// 至少满足 min，否则失败
		if len(cca) >= node.MinRange {
			// 是否 min == 0
			if len(cca) == 0 {
				return true, newAlphaMatchRangeIgnore(nowPos)
			}

			return true, newAlphaMatchRangeFromChildren(cca)
		}

		tw.SetPos(nowPos) // 回溯
		return false, nil

	default:
		panic("未知的正则表达式节点： " + fmt.Sprint(t))
	}
}
